﻿using System;
using System.ComponentModel;

namespace Utils
{
    public static class ConverterHelper
    {
        #region 尝试将对象转换为指定的类型 转换失败则返回默认值


        /// <summary>
        /// 尝试将对象转换为指定的类型 转换失败则返回默认值
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="obj">待转换对象</param>
        /// <param name="defaultValue">转换失败时返回的默认值</param>
        /// <returns>转换的目标对象</returns> 
        public static T ToType<T>(this object obj, T defaultValue)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            try
            {
                if (obj is T t)
                {
                    return t;
                }
                var type = typeof(T);
                if (type.IsValueType)
                {
                    type = Nullable.GetUnderlyingType(type) ?? type;
                }
                return (T)Convert.ChangeType(obj, type);
            }
            catch
            {
                return defaultValue;
            }
        }

        /// <summary>
        /// 尝试将对象转换为指定的类型 转换失败则返回default(T)
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="obj">待转换对象</param>
        /// <returns>转换的目标对象</returns> 
        public static T ToType<T>(this object obj)
        {
            return ToType<T>(obj, default);
        }

        /// <summary>
        /// 尝试转换类型
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool TryChangeType(this Type type, ref object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return false;
            }
            else if (type.IsAssignableFrom(obj.GetType()))
            {
                return true;
            }
            else
            {
                if (type.IsValueType)
                {
                    type = Nullable.GetUnderlyingType(type) ?? type;
                }
                try
                {
                    obj = Convert.ChangeType(obj, type);
                }
                catch
                {
                    return false;
                }
            }
            return true;
        }
        #endregion

        #region 将字符串转换为整数(int)

        /// <summary>
        /// 将日期按照指定的格式转换为数字
        /// </summary>
        /// <param name="dateTime">待转换日期</param>
        /// <param name="format">转换格式</param>
        /// <returns>转换的结果,转换失败则返回0</returns>
        public static int ToInt(this DateTime dateTime, string format = "yyyyMMdd")
        {
            int result;
            Int32.TryParse(dateTime.ToString(format, System.Globalization.DateTimeFormatInfo.InvariantInfo), out result);
            return result;
        }

        public static int? ToInt(this DateTime? dateTime, string format = "yyyyMMdd")
        {
            if (dateTime.HasValue)
            {
                return ToInt(dateTime.Value, format);
            }
            return null;
        }


        /// <summary>
        /// 将日期按照指定的格式转换为数字
        /// </summary>
        /// <param name="dateTime">待转换日期</param>
        /// <param name="format">转换格式</param>
        /// <returns>转换的结果,转换失败则返回0</returns>
        public static DateTime ToDate(this int date, string format = "yyyyMMdd")
        {
            DateTime result;
            if (DateTime.TryParseExact(date.ToString(), format, System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None, out result))
            {
                return result;
            }
            return DateTime.MinValue;
        }


        /// <summary>
        /// 将字符串转换为数字(int)
        /// </summary>
        /// <param name="str">待转换字符</param>
        ///  <param name="defaultval">转换失败时，返回默认值</param>
        /// <returns>返回转换后的值</returns>
        /// <example>
        /// <code lang="c#">
        /// <![CDATA[
        ///     string str="123";
        ///     int ret=str.ToInt32(0); //return 123
        ///     
        ///     str="abc";
        ///     ret=abc.ToInt32(); //return 0;
        /// ]]>
        /// </code>
        /// </example>
        public static int ToInt32(this string str, int defaultval = 0)
        {
            int result;
            if (int.TryParse(str, out result))
            {
                return result;
            }
            return defaultval;
        }
        #endregion


        /// <summary>
        /// 将字符串转换为数字(Long)
        /// </summary>
        /// <param name="str">待转换字符</param>
        ///  <param name="defaultval">转换失败时，返回默认值</param>
        /// <returns>返回转换后的值</returns>
        /// <example>
        /// <code lang="c#">
        /// <![CDATA[
        /// string str="123456789012";
        /// long ret=str.ToInt64();// 返回：123456789012
        /// ]]>
        /// </code>
        /// </example>
        public static long ToInt64(this string str, long defaultval = 0)
        {
            long result;
            if (long.TryParse(str, out result))
            {
                return result;
            }
            return defaultval;
        }

        #region 将字符串分割成int数组
        /// <summary>
        /// 将字符串分割成int数组
        /// </summary>
        /// <param name="str">待转换字符</param>
        /// <param name="splitChar">分隔符</param>
        /// <returns>返回整数数组</returns>
        /// <example>
        ///<code lange="c#">
        ///<![CDATA[
        /// string str="1,2,a,4";
        /// int[] ret=str.ToIntArray(); //return:[1,2,0,4];
        /// ]]>
        /// </code>
        /// </example>
        public static int[] ToIntArray(this string str, string splitChar = ",")
        {
            if (string.IsNullOrEmpty(str) || string.IsNullOrEmpty(splitChar))
            {
                return new int[0];
            }
            string[] strArray = str.Split(new string[] { splitChar }, StringSplitOptions.RemoveEmptyEntries);
            if (strArray.Length == 0)
            {
                return new int[0];
            }
            return Array.ConvertAll(strArray, s => s.ToInt32());
        }

        #endregion


        #region 日期转换

        /// <summary>
        /// 时间格式化成字符串
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static string FormatString(this DateTime dateTime, string format = "yyyy-MM-dd HH:mm:ss")
        {
            return dateTime.ToString(format);
        }
        /// <summary>
        /// 字符串转换为日期
        /// </summary>
        /// <param name="str">待转换字符</param>
        /// <param name="result">转换结果</param>
        /// <param name="format">日期格式</param>
        /// <returns>是否转换成功,若转换失败，out日期为1900-01-01</returns>
        /// <example>
        /// <![CDATA[
        /// string str="2104-08-28";
        /// DateTime dt;
        /// bool successed=str.TryToDate(out dt);
        /// 
        /// str="20140828081559";
        /// successed=str.TryToDate(out dt,"yyyyMMddHHmmss");    //dt:2014-08-28 08:15:59
        /// 
        /// str="123";
        /// successed=str.TryToDate(out dt); //false, dt:1900-01-01
        /// ]]>
        /// </example>
        public static bool TryToDate(this string str, out DateTime result, string format = "yyyy-MM-dd")
        {
            result = DateTime.MinValue;
            if (DateTime.TryParse(str, out result))
            {
                return true;
            }
            if (string.IsNullOrEmpty(format))
            {
                format = "yyyy-MM-dd";
            }
            if (string.IsNullOrEmpty(str) || str.Length != format.Length)
            {
                return false;
            }

            bool flag = DateTime.TryParseExact(str, format,
                System.Globalization.DateTimeFormatInfo.InvariantInfo,
                System.Globalization.DateTimeStyles.None, out result);
            if (!flag)
            {
                result = DateTime.MinValue;
            }
            return flag;
        }

        /// <summary>
        ///  字符串转换为日期
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="format">日期格式</param>
        /// <returns>日期</returns>
        public static DateTime ToDateTime(this string str, string format = "yyyy-MM-dd")
        {
            DateTime result;
            if (str.TryToDate(out result, format))
            {
                return result;
            }

            return result;
        }

        /// <summary>
        /// 转本地时间
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static DateTime ToLocalTime(this DateTime dt)
        {
            return TimeZoneInfo.ConvertTime(dt, TimeZoneInfo.Utc, TimeZoneInfo.Local).ToLocalTime();
        }

        /// <summary>
        /// 转秒时间戳
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static long ToUnixTimestamp(this DateTime dateTime)
        {
            DateTime startTime = ToLocalTime(new DateTime(1970, 1, 1));
            return (long)(dateTime - startTime).TotalSeconds;
        }

        #endregion


        #region 将传入值转换为bool类型
        /// <summary>
        /// 将传入值转换为bool类型
        /// </summary>
        /// <param name="input">待转换值</param>
        /// <param name="defValue">默认值，默认返回false</param>
        /// <returns>转换后的值</returns>
        /// <example>
        /// <code lang="c#">
        /// <![CDATA[
        ///     string str="1";
        ///     bool ret=str.ToBool();  //TRUE;
        ///     
        ///     str="true";
        ///     ret=str.ToBool();       //TRUE;
        ///     
        ///     str="0";
        ///     ret=str.ToBool();       //False;
        ///     
        ///     str="false";
        ///     ret=str.ToBool();       //False;
        /// ]]>
        /// </code>
        /// </example>
        public static bool ToBool(this string input, bool defValue = false)
        {
            if (string.IsNullOrEmpty(input))
            {
                return defValue;
            }
            if (bool.TryParse(input, out bool result))
            {
                return result;
            }
            return defValue;
        }
        #endregion

        #region 将传入值转换为float类型
        /// <summary>
        /// 将传入值转换为float类型
        /// </summary>
        /// <param name="input">待转换值</param>
        /// <param name="defValue">默认值</param>
        /// <returns>转换后的值</returns>
        /// <example>
        /// <code lang="c#">
        /// <![CDATA[
        ///     string str="123.1";
        ///     float ret=str.ToFloat();
        ///     
        ///     int i=123;
        ///     ret=i.ToFloat();
        /// ]]>
        /// </code>
        /// </example>
        public static float ToFloat(this string input, float defValue = 0f)
        {
            if (input == null)
            {
                return defValue;
            }
            if (float.TryParse(input, out float result))
            {
                return result;
            }
            return defValue;
        }
        #endregion

        #region  将传入值转换为double类型
        /// <summary>
        /// 将传入值转换为double类型
        /// </summary>
        /// <param name="input">待转换值</param>
        /// <param name="defValue">默认值</param>
        /// <returns>转换后的值</returns>
        /// <example>
        /// <code lang="c#">
        /// <![CDATA[
        ///     string str="123.1";
        ///     float ret=str.ToDouble();
        ///     
        ///     int i=123;
        ///     ret=i.ToDouble();
        /// ]]>
        /// </code>
        /// </example>
        public static double ToDouble(this string input, double defValue = 0.0)
        {
            if (input == null)
            {
                return defValue;
            }
            if (double.TryParse(input, out double result))
            {
                return result;
            }
            return defValue;
        }
        #endregion

        #region 将传入值转换为decimal类型
        /// <summary>
        /// 将传入值转换为decimal类型
        /// </summary>
        /// <param name="input">待转换值</param>
        /// <param name="defValue">默认值</param>
        /// <returns>转换后的值</returns>
        public static decimal ToDecimal(this string input, decimal defValue = 0M)
        {
            if (input == null)
            {
                return defValue;
            }
            if (decimal.TryParse(input, out decimal result))
            {
                return result;
            }
            return defValue;
        }

        #endregion
    }

}
